package org.javaforever.gatescore.shiroauth;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.List;

import org.javaforever.gatescore.core.FrontDomain;
import org.javaforever.gatescore.core.FrontDropdown;
import org.javaforever.gatescore.core.FrontManyToMany;
import org.javaforever.gatescore.core.FrontPrism;
import org.javaforever.gatescore.core.FrontVerb;
import org.javaforever.gatescore.core.Module;
import org.javaforever.gatescore.core.ValidateInfo;
import org.javaforever.gatescore.exception.ValidateException;
import org.javaforever.gatescore.shiroauth.verb.AddUser;
import org.javaforever.gatescore.shiroauth.verb.ChangeMyPasswordUser;
import org.javaforever.gatescore.shiroauth.verb.ChangePasswordUser;
import org.javaforever.gatescore.shiroauth.verb.FindMyProfileUser;
import org.javaforever.gatescore.shiroauth.verb.LoginUser;
import org.javaforever.gatescore.shiroauth.verb.LogoutUser;
import org.javaforever.gatescore.shiroauth.verb.ReadMySession;
import org.javaforever.gatescore.shiroauth.verb.RegisterUser;
import org.javaforever.gatescore.shiroauth.verb.UpdateMyProfileUser;
import org.javaforever.gatescore.shiroauth.vue.ElementUIProfilePage;
import org.javaforever.gatescore.shiroauth.vue.ElementUIRegisterUserPage;
import org.javaforever.gatescore.shiroauth.vue.ElementUIUserPage;
import org.javaforever.gatescore.shiroauth.vue.UsersStoreJSGenerator;
import org.javaforever.gatescore.vue.ElementUILoginPage;
import org.javaforever.gatescore.vue.ElementUIMtmPage;
import org.javaforever.gatescore.vue.ElementUIPage;
import org.javaforever.gatescore.vue.VueAPIJs;

public class ShiroAuthModule extends Module{
	protected FrontDomain userDomain;
	protected FrontDomain roleDomain;
	protected FrontDomain privilegeDomain;
	protected FrontPrism loginPrism;
	protected FrontPrism userPrism;
	protected FrontPrism rolePrism;
	protected FrontPrism privilegePrism;
	protected FrontPrism profilePrism;

	public FrontPrism getProfilePrism() {
		return profilePrism;
	}

	public void setProfilePrism(FrontPrism profilePrism) {
		this.profilePrism = profilePrism;
	}

	public ShiroAuthModule() {
		super();
		this.standardName = "ShiroAuth";
	}
	
	public boolean validateDomains() throws ValidateException{
		ValidateInfo info = new ValidateInfo();
//		if (userDomain==null||roleDomain==null||privilegeDomain==null) {
//			info.addCompileError("所需域对象缺失！");			
//		}
//		if (userDomain.findFieldByFixedName("userName")==null||!userDomain.findFieldByFixedName("userName").getFieldType().getTypeName().equalsIgnoreCase("String")) {
//			info.addCompileError("用户域对象固定名字userName字段设置有问题！");			
//		}
//		if (userDomain.findFieldByFixedName("password")==null||!userDomain.findFieldByFixedName("password").getFieldType().getTypeName().equalsIgnoreCase("String")
//				||(!StringUtil.isBlank(userDomain.findFieldByFixedName("password").getLengthStr())&&Integer.parseInt(userDomain.findFieldByFixedName("password").getLengthStr())<40)){
//			info.addCompileError("用户域对象固定名字password字段设置有问题！");			
//		}	
//		if (userDomain.findFieldByFixedName("salt")==null||!userDomain.findFieldByFixedName("salt").getFieldType().getTypeName().equalsIgnoreCase("String")
//				||(!StringUtil.isBlank(userDomain.findFieldByFixedName("salt").getLengthStr())&&Integer.parseInt(userDomain.findFieldByFixedName("salt").getLengthStr())<8)){
//			info.addCompileError("用户域对象固定名字salt字段设置有问题！");			
//		}	
//		if (userDomain.findFieldByFixedName("loginFailure")==null||!userDomain.findFieldByFixedName("loginFailure").getFieldType().getTypeName().equalsIgnoreCase("Integer")){
//			info.addCompileError("用户域对象固定名字loginFailure字段设置有问题！");			
//		}	
//		if (roleDomain.findFieldByFixedName("roleName")==null||!roleDomain.findFieldByFixedName("roleName").getFieldType().equalsIgnoreCase("String")) {
//			info.addCompileError("角色域对象roleName字段设置有问题！");			
//		}		
		if (info.success(false))	return true;
		else throw new ValidateException(info);
	}
	
	public boolean validateDataDomains() throws ValidateException{
		ValidateInfo info = new ValidateInfo();
		if (info.success(false))	return true;
		else throw new ValidateException(info);
	}

	@Override
	public void generateModuleFiles(String targetFolderPath) throws Exception {
		generateLoginPrismFiles(targetFolderPath);
		generateUserPrismFiles(targetFolderPath);	
		generateProfilePrismFiles(targetFolderPath);	
	}
	
	public void generateLoginPrismFiles(String targetFolderPath) throws Exception {
		for (ElementUIPage etp:this.loginPrism.getPages()) {
			writeToFile(targetFolderPath + "src/views/login/" + etp.getFileName(),
					etp.generateStatementList().getContent());
		}
		writeToFile(targetFolderPath + "src/api/" + this.loginPrism.getApi().getFileName(),
				 this.loginPrism.getApi().generateStatementList().getContent());
		UsersStoreJSGenerator usrjsg = new UsersStoreJSGenerator(this.userDomain);
		writeToFile(targetFolderPath + "src/store/modules/" + usrjsg.getFileName(),
				usrjsg.generateStatementList().getContent());
	}
	
	public void generateUserPrismFiles(String targetFolderPath) throws Exception {
		ValidateInfo info = this.userPrism.validate();
		if (info.success(false) == false) {
			ValidateException e = new ValidateException(info);
			throw e;
		}
		try {
			for (ElementUIPage etp:this.userPrism.getPages()) {
				ElementUIUserPage uetp = (ElementUIUserPage)etp;
				writeToFile(targetFolderPath + "src/views/pages/" + this.userDomain.getPlural().toLowerCase() + ".vue",
						uetp.generateStatementList().getContent());
			}
			
			writeToFile(targetFolderPath + "src/api/" + this.userPrism.getApi().getFileName(),
					this.userPrism.getApi().generateStatementList().getContent());
				
			for (FrontManyToMany mtm : this.userPrism.getManyToManies()) {
				if (!mtm.getMaster().isLegacy()&&!mtm.getSlave().isLegacy()) { 
					ElementUIMtmPage mtmp = new ElementUIMtmPage(mtm);
					writeToFile(targetFolderPath + "src/views/pages/" + mtm.getStandardName().toLowerCase() + ".vue",
							mtmp.generateStatementList().getContent());
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void generateProfilePrismFiles(String targetFolderPath) throws Exception {
		ValidateInfo info = this.profilePrism.validate();
		if (info.success(false) == false) {
			ValidateException e = new ValidateException(info);
			throw e;
		}
		try {
			for (ElementUIPage etp:this.profilePrism.getPages()) {
				ElementUIProfilePage uetp = (ElementUIProfilePage)etp;
				writeToFile(targetFolderPath + "src/views/pages/profile.vue",
						uetp.generateStatementList().getContent());
			}
			
			writeToFile(targetFolderPath + "src/api/" + this.profilePrism.getApi().getFileName(),
					this.profilePrism.getApi().generateStatementList().getContent());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void generatePrismsFromDomians() throws Exception {
		generateLoginPrismFromUserDomain(true);
		generateUserPrismFromUserDomain(true);
		generateProfilePrismFromUserDomain(true);	
	}
	
	public void generateProfilePrismFromUserDomain(Boolean ignoreWarning) throws ValidateException, Exception {
		if (this.userDomain != null) {
			this.profilePrism = new FrontPrism();
			this.profilePrism.setStandardName("ProfilePrism");
			this.profilePrism.setDomain(this.userDomain);
			FindMyProfileUser find = new FindMyProfileUser(this.userDomain);
			UpdateMyProfileUser update = new UpdateMyProfileUser(this.userDomain);
			ChangeMyPasswordUser change = new ChangeMyPasswordUser(this.userDomain);
			this.profilePrism.addVerb(find);
			this.profilePrism.addVerb(update);
			this.profilePrism.addVerb(change);
			
			VueAPIJs vapi = new VueAPIJs(this.userDomain);
			vapi.setStandardName("profile");
			vapi.setUseLoginBaseUri(false);
			vapi.addVerb(find);
			vapi.addVerb(update);
			vapi.addVerb(change);
			this.profilePrism.setApi(vapi);
			
			for (FrontDropdown dp:this.userDomain.getDropdownSet()) {
				org.javaforever.gatescore.shiroauth.verb.ListActive listActive = new org.javaforever.gatescore.shiroauth.verb.ListActive(dp.getTarget());
				listActive.setProfileController(true);
				
				vapi.addVerb(listActive);
			}
			this.profilePrism.setApi(vapi);
			
			this.profilePrism.getApi().addVerb(find);
			this.profilePrism.getApi().addVerb(update);
			this.profilePrism.getApi().addVerb(change);
			
			ElementUIProfilePage etp = new ElementUIProfilePage(this.userDomain);
			this.profilePrism.addPage(etp);
		}
	}
	
	public void generateLoginPrismFromUserDomain(Boolean ignoreWarning) throws ValidateException, Exception {
		this.loginPrism = new FrontPrism();
		this.loginPrism.setDomain(this.userDomain);
		this.loginPrism.setStandardName("LoginPrism");
		
		ElementUILoginPage etp = new ElementUILoginPage();
		etp.setDomain(this.userDomain);
		etp.setFileName("index.vue");
		etp.setStandardName("Login");
		this.loginPrism.addPage(etp);
		
		ElementUIRegisterUserPage reg = new ElementUIRegisterUserPage();
		reg.setDomain(this.userDomain);
		reg.setFileName("register.vue");
		reg.setStanadardName("Register");
		this.loginPrism.addPage(reg);
		
//		etp.setVerbs(this.verbs);
//		etp.setTwinsverbs(this.twinsverbs);
		
		VueAPIJs vapi = new VueAPIJs(this.userDomain);
		vapi.setStandardName("login");
		vapi.setUseLoginBaseUri(true);
		FrontVerb loginUser = new LoginUser(this.userDomain);
		FrontVerb logoutUser = new LogoutUser(this.userDomain);
		FrontVerb readMySession = new ReadMySession(this.userDomain);
		FrontVerb registerUser = new RegisterUser(this.userDomain);
		vapi.addVerb(loginUser);
		vapi.addVerb(logoutUser);
		vapi.addVerb(readMySession);
		vapi.addVerb(registerUser);
		
		for (FrontDropdown dp:this.userDomain.getDropdownSet()) {
			FrontVerb listActive = new org.javaforever.gatescore.shiroauth.verb.ListActive(dp.getTarget());
			vapi.addVerb(listActive);
		}
		this.loginPrism.setApi(vapi);
	}

	public static String packagetokenToFolder(String packageToken) {
		String folder = packageToken.replace('.', '/');
		folder += "/";
		return folder;
	}
	
	public static String folderToPackageToken(String folder) {
		String packagetoken = folder.replace('/', '.');
		if (packagetoken.charAt(packagetoken.length() - 1) == '.')
			packagetoken = packagetoken.substring(0, packagetoken.length() - 1);
		return packagetoken;
	}
	
	public void writeToFile(String filePath, String content) throws Exception {
		File f = new File(filePath);
		if (!f.getParentFile().exists()) {
			f.getParentFile().mkdirs();
		}
		f.createNewFile();
		try (Writer fw = new BufferedWriter(
				new OutputStreamWriter(new FileOutputStream(f.getAbsolutePath()), "UTF-8"))) {
			fw.write(content, 0, content.length());
		}
	}
	
	public void generatePrismFiles(FrontPrism prism,Boolean ignoreWarning,Boolean genUi,Boolean genController,Boolean genService,Boolean genServiceImpl,Boolean genDao,Boolean genDaoImpl) throws ValidateException {
		ValidateInfo info = prism.validate();
		if (info.success(ignoreWarning) == false) {
			ValidateException e = new ValidateException(info);
			throw e;
		}
	}	
	
	public void generateUserPrismFromUserDomain(Boolean ignoreWarning) throws ValidateException, Exception {
		if (this.userDomain != null) {
			this.userPrism = new FrontPrism();
			this.userPrism.setStandardName("UserPrism");
			this.userPrism.setDomain(this.userDomain);
			this.userPrism.setProjectDomains(this.domains);
			this.userPrism.generatePrismFromDomain();
			this.userPrism.removeVerb("Add"+this.userDomain.getCapFirstDomainName());
			this.userPrism.removePage(this.userDomain.getPlural());
			AddUser addUser = new AddUser(this.userDomain);
			this.userPrism.addVerb(addUser);
			this.userPrism.getApi().addVerb(addUser);
			ChangePasswordUser cpu = new ChangePasswordUser(this.userDomain);
			this.userPrism.addVerb(cpu);
			this.userPrism.getApi().addVerb(cpu);
			ElementUIUserPage etp = new ElementUIUserPage(this.userDomain);
			etp.setVerbs(this.userPrism.getVerbs());
			etp.setTwinsverbs(this.userPrism.getTwinsverbs());
			this.userPrism.addPage(etp);
		}
	}

	@Override
	public List<List<FrontDomain>> decorateDataDomains(List<List<FrontDomain>> dataDomains) throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

	public FrontDomain getUserDomain() {
		return userDomain;
	}

	public void setUserDomain(FrontDomain userDomain) {
		this.userDomain = userDomain;
	}

	public FrontDomain getRoleDomain() {
		return roleDomain;
	}

	public void setRoleDomain(FrontDomain roleDomain) {
		this.roleDomain = roleDomain;
	}

	public FrontDomain getPrivilegeDomain() {
		return privilegeDomain;
	}

	public void setPrivilegeDomain(FrontDomain privilegeDomain) {
		this.privilegeDomain = privilegeDomain;
	}

	public FrontPrism getLoginPrism() {
		return loginPrism;
	}

	public void setLoginPrism(FrontPrism loginPrism) {
		this.loginPrism = loginPrism;
	}

	public FrontPrism getUserPrism() {
		return userPrism;
	}

	public void setUserPrism(FrontPrism userPrism) {
		this.userPrism = userPrism;
	}

	public FrontPrism getRolePrism() {
		return rolePrism;
	}

	public void setRolePrism(FrontPrism rolePrism) {
		this.rolePrism = rolePrism;
	}

	public FrontPrism getPrivilegePrism() {
		return privilegePrism;
	}

	public void setPrivilegePrism(FrontPrism privilegePrism) {
		this.privilegePrism = privilegePrism;
	}
}
